if (!window["vg"]) {
    window["vg"] = {};
}
if (!vg.visualization) {
    vg.visualization = {};
}
/**
 * To create a workflow viewer
 * @param {Object} inputObj
 */
vg.visualization.WorkflowViewer = function(inputObj){
    this.stateNames = inputObj.stateNames;
    this.container = inputObj.container.length ? document.getElementById(inputObj.container) : inputObj.container;
	this.colors = inputObj.colors || {};
	if(!this.colors.arrowEnabled){
		this.colors.arrowEnabled = "#1F497D";
	}
	if(!this.colors.arrowDisabled){
		this.colors.arrowDisabled = "#8DB3E2";
	}
	this.numReturns;
}

vg.visualization.WorkflowViewer.prototype = (function(){
	/**
	 * Object that stores all the classes used in the view
	 */
	var classObject = {
		state : "workflow-state",
		completed : "state-completed",
		active : "state-active",
		notreached : "state-notreached"
	}
	
	var dimensions = {
		arrowHeight : 15,
		arrowWidth : 6,
		stateRow : "20px",
		stateCellWidth : 120,
		stateCellHeight : 60
	}
	
	//calling the function to add classes to the HTML page
    setStyle();
    
    /**
     * Adds some CSS classes to the current document to be used by the menu div
     */
    function setStyle(){
        var style = '.workflow-table td {border-spacing : 0px;}\
                   	.workflow-state {text-align: center;vertical-align: middle;font-family: arial,helvetica;cursor: default;-moz-border-radius: 5px;-webkit-border-radius : 5px;font-size : small;font-weight : bold;}\
                    .state-completed {border: 3px solid #1F497D;background-color: #548DD4;color : #ffffff;}\
                    .state-active {border: 3px solid #4E6128;background-color: #9BBB59;color : #ffffff;}\
					.state-notreached {border: 3px solid #8DB3E2;background-color: #C6D9F1;color : #ffffff;}';
        var styleElmt = document.createElement("style");
        styleElmt.setAttribute("type", "text/css");
        if (styleElmt.styleSheet) {			//for IE
			styleElmt.styleSheet.cssText = style;
		} else {							//the browsers
			styleElmt.innerHTML = style;
		}
        document.getElementsByTagName("head")[0].appendChild(styleElmt);
    }
	
	/**
	 * To insert a number of cells to a row. The widts array specifies the widths of each of the cells
	 * @param {Object} row
	 * @param {Object} numCells
	 * @param {Object} widths
	 */
    var insertCells = function(row, numCells, widths){
        for (var i = 0; i < numCells; i++) {
            var cell = row.insertCell(-1);
			if(widths && widths[i]) {
				cell.style.width = widths[i] + (/px/.test(widths[i]) ? "" : "px");
			}
        }
    }
    
	/**
	 * To create a HTML tag
	 * @param {Object} inputObj - properties - tagName, parent, styles
	 */
    var createTag = function(inputObj){
        var element = document.createElement(inputObj.tagName);
        inputObj.parent && inputObj.parent.appendChild(element);
		if(inputObj.className) {
			element.className = inputObj.className;
		}
        if (inputObj.styles) {
            for (var i in inputObj.styles) {
                element.style[i] = inputObj.styles[i];
            }
        }
		if(inputObj.attributes) {
			for( var j in inputObj.attributes) {
				element.setAttribute(j, inputObj.attributes[j]);
			}
		}
		return element;
    }	
    
	/**
	 * This object is returned from this closure which acts as the prototype for the WorkflowViewer class
	 */
    var workflow = (function(){
        var draw = function(){
        	this.table = createTag({
				tagName : "table",
				parent : this.container,
				className : "workflow-table"
			});
			this.table.cellSpacing = 0;
			this.table.cellPadding = 0;
			var tBody = createTag({
				tagName : "tbody",
				parent : this.table
			});
			this.states = [];
			insertTopRow(this.table);
			for (var i = 0; i < this.stateNames.length; i++) {
				this.states.push(new State({
					isFirstState : (i == 0 ? true : false),
					isLastState : (i == (this.stateNames.length - 1) ? true : false),
					workflowViewer : this,
					name : this.stateNames[i],
					status : "notreached"					
				}));
			}
			this.states[2].drawArrowHead("top", true);
        }
        
		var insertTopRow = function (table) {
			var row = table.insertRow(-1);
			insertCells(row, 8, [10,15,dimensions.arrowHeight,60,60,dimensions.arrowHeight,15,10]);
			return row;
		}
       
        return {
            draw: draw
        }
    })();
    
	/**
	 * Inner class state that is used to represent a state and its surrounding cells
	 * @param {Object} inputObj
	 */
	var State = function (inputObj) {
		this.workflowViewer = inputObj.workflowViewer;
		this.table = this.workflowViewer.table;
		this.name = inputObj.name;
		this.status = inputObj.status;
		this.isLastState = inputObj.isLastState;
		this.isFirstState = inputObj.isFirstState;
		this.canvases = {};
		this.draw();
	}
	
	/**
	 * Prototype for the State class
	 */
	State.prototype = (function () {
		var draw = function () {
			if(!this.isFirstState) {
				this.firstRow = this.table.insertRow(-1);
				insertCells(this.firstRow, 8);
				insertCanvas(this, "top");
				this.firstRow.style.height = dimensions.arrowHeight + "px";
			}
			this.secondRow = this.table.insertRow(-1);
			insertCells(this.secondRow, 7);
			this.stateCell = this.secondRow.cells[3];
			this.stateCell.colSpan = 2;
			this.stateCell.rowSpan = 3;
			this.stateCell.innerHTML = this.name;
			this.secondRow.style.height = dimensions.stateRow;
			this.thirdRow = this.table.insertRow(-1);
			insertCells(this.thirdRow, 6);
			this.thirdRow.style.height = dimensions.stateRow;
			this.fourthRow = this.table.insertRow(-1);
			insertCells(this.fourthRow, 6);
			this.fourthRow.style.height = dimensions.stateRow;			
			insertCanvas(this, "left");
			insertCanvas(this, "right");
			if(!this.isLastState) {
				this.fifthRow = this.table.insertRow(-1);
				insertCells(this.fifthRow, 8);
				this.fifthRow.style.height = dimensions.arrowHeight + "px";			
			}
			this.setStatus(this.status);
		}
		
		var setStatus = function (status) {
			var statusColor = this.workflowViewer.colors && this.workflowViewer.colors[status];
			if(statusColor) {
				this.stateCell.backgroundColor = statusColor.background;
				this.stateCell.border = statusColor.border;
				this.stateCell.color = statusColor.color;
			} else {
				this.stateCell.className = classObject.state + " " + classObject[status];
			}
		}
		
		/**
		 * To insert canvases fordrawin arrow heads
		 * @param {Object} orientation
		 */
		var insertCanvas = function (stateObj, orientation) {
			if(orientation == "top") {
				stateObj.canvases.top = {
					left : createTag({
						tagName : "canvas",
						parent : stateObj.firstRow.cells[3],
						attributes : {
							width : dimensions.stateCellWidth/2,
							height : dimensions.arrowHeight
						}					
					}),
					right : createTag({
						tagName : "canvas",
						parent : stateObj.firstRow.cells[4],
						attributes : {
							width : dimensions.stateCellWidth/2,
							height : dimensions.arrowHeight
						}
					})
				}
			} else if (orientation == "left") {
				stateObj.canvases.left = {
					top : createTag({
						tagName : "canvas",
						parent : stateObj.thirdRow.cells[2],
						attributes : {
							width : dimensions.arrowHeight,
							height : dimensions.stateCellHeight/3
						}					
					}),
					bottom : createTag({
						tagName : "canvas",
						parent : stateObj.fourthRow.cells[2],
						attributes : {
							width : dimensions.arrowHeight,
							height : dimensions.stateCellHeight/3
						}					
					})
				}
			} else {
				stateObj.canvases.right = {
					top : createTag({
						tagName : "canvas",
						parent : stateObj.secondRow.cells[4],
						attributes : {
							width : dimensions.arrowHeight,
							height : dimensions.stateCellHeight/3
						}					
					}),
					bottom : createTag({
						tagName : "canvas",
						parent : stateObj.thirdRow.cells[3],
						attributes : {
							width : dimensions.arrowHeight,
							height : dimensions.stateCellHeight/3
						}					
					})
				}				
			}
		}
		/**
		 * Draw an arrow head in the canvas
		 * @param {Object} orientation - top, left, right
		 */
		var drawArrowHead = function (orientation, isEnabled) {
			var canvases = this.canvases[orientation];
			var color = this.workflowViewer.colors[isEnabled ? "arrowEnabled" : "arrowDisabled"];
			var sideCellHeight = dimensions.stateCellHeight/3;
			var topCellWidth = dimensions.stateCellWidth/2;
			if (orientation == "top") {
				drawTriangle(canvases.left, [[topCellWidth,0], [topCellWidth - dimensions.arrowWidth/2,0], [topCellWidth,dimensions.arrowHeight]], color);
				drawTriangle(canvases.right, [[0,0], [dimensions.arrowWidth/2,0], [0,dimensions.arrowHeight]], color);
			} else if (orientation == "left") {
				drawTriangle(canvases.top, [[0,sideCellHeight],[0,sideCellHeight - dimensions.arrowWidth/2],[dimensions.arrowHeight, sideCellHeight]], color);
				drawTriangle(canvases.bottom, [[0,0],[0,dimensions.arrowWidth/2],[dimensions.arrowHeight, 0]], color);				
			} else {
				drawTriangle(canvases.top, [[0,sideCellHeight],[dimensions.arrowHeight,sideCellHeight],[dimensions.arrowHeight,sideCellHeight - dimensions.arrowWidth/2]], color);
				drawTriangle(canvases.bottom, [[0,0],[dimensions.arrowHeight,0],[dimensions.arrowHeight,dimensions.arrowWidth/2]], color);				
			}
		}
		
		var drawTriangle = function (canvas, coordinates, color) {
			 if (canvas.getContext) {
			 	var ctx = canvas.getContext("2d");
			 	ctx.beginPath();
			 	ctx.moveTo(coordinates[0][0], coordinates[0][1]);
			 	ctx.lineTo(coordinates[1][0], coordinates[1][1]);
			 	ctx.lineTo(coordinates[2][0], coordinates[2][1]);
                ctx.fillStyle = color;  
                ctx.fill();				
			 }		
		}
		return  {
			draw : draw,
			setStatus : setStatus,
			drawArrowHead : drawArrowHead
		}
	})();
		
    return workflow;
})();